package sf.database.jdbc.type;

import sf.database.dbinfo.Feature;
import sf.database.dialect.DBDialect;
import sf.database.util.DBUtils;
import sf.tools.IOUtils;

import javax.persistence.PersistenceException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

/**
 * sqlite 不支持blob类型
 */
public class FileBlobType implements TypeHandler<File> {

    public File get(ResultSet rs, String columnName) throws SQLException {
        Object object = rs.getObject(columnName);
        return valueToFile(object);
    }

    public File get(ResultSet rs, int index) throws SQLException {
        Object object = rs.getObject(index);
        return valueToFile(object);
    }

    public File get(CallableStatement rs, int index) throws SQLException {
        Object object = rs.getObject(index);
        return valueToFile(object);
    }

    @Override
    public File get(CallableStatement cs, String parameterName) throws SQLException {
        Object object = cs.getObject(parameterName);
        return valueToFile(object);
    }

    public Object set(PreparedStatement ps, Object obj, int i) throws SQLException {
        DBDialect dialect = DBUtils.doGetDialect(ps.getConnection(), false);
        File file = (File) obj;
        if (null == obj) {
            if (dialect.has(Feature.NOT_SUPPORT_SET_BINARY)) {
                ps.setNull(i, Types.BINARY);
            } else {
                ps.setNull(i, getSqlType());
            }
        } else {
            try {
                if (dialect.has(Feature.NOT_SUPPORT_SET_BINARY)) {
                    ps.setBytes(i, IOUtils.toByteArray(file));
                } else {
                    ps.setBinaryStream(i, IOUtils.getInputStream(file), file.length());
                }
            } catch (IOException e) {
                throw new PersistenceException(e);
            }
        }
        return null;
    }

    @Override
    public Object set(CallableStatement cs, Object obj, String parameterName) throws SQLException {
        DBDialect dialect = DBUtils.doGetDialect(cs.getConnection(), false);
        File file = (File) obj;
        if (null == obj) {
            if (dialect.has(Feature.NOT_SUPPORT_SET_BINARY)) {
                cs.setNull(parameterName, Types.BINARY);
            } else {
                cs.setNull(parameterName, getSqlType());
            }
        } else {
            try {
                if (dialect.has(Feature.NOT_SUPPORT_SET_BINARY)) {
                    cs.setBytes(parameterName, IOUtils.toByteArray(file));
                } else {
                    cs.setBinaryStream(parameterName, IOUtils.getInputStream(file), file.length());
                }
            } catch (IOException e) {
                throw new PersistenceException(e);
            }
        }
        return null;
    }

    @Override
    public void update(ResultSet rs, String columnLabel, Object value) throws SQLException {
        DBDialect dialect = DBUtils.doGetDialect(rs.getStatement().getConnection(), false);
        File file=(File)value;
        try {
            if(dialect.has(Feature.NOT_SUPPORT_SET_BINARY)){
                rs.updateBytes(columnLabel, IOUtils.toByteArray(file));
            }else{
                rs.updateBinaryStream(columnLabel, IOUtils.getInputStream(file),file.length());
            }
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    @Override
    public void update(ResultSet rs, int columnIndex, Object value) throws SQLException {
        DBDialect dialect = DBUtils.doGetDialect(rs.getStatement().getConnection(), false);
        File file=(File)value;
        try {
            if(dialect.has(Feature.NOT_SUPPORT_SET_BINARY)){
                rs.updateBytes(columnIndex, IOUtils.toByteArray(file));
            }else{
                rs.updateBinaryStream(columnIndex, IOUtils.getInputStream(file),file.length());
            }
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    public int getSqlType() {
        return Types.BLOB;
    }

    @Override
    public Class<File> getDefaultJavaType() {
        return File.class;
    }


    public File valueToFile(Object obj) throws SQLException {
        if (obj == null) return null;
        if (obj.getClass().isArray()) {
            try {
                File file = File.createTempFile("tmp", ".io");
                IOUtils.saveAsFile(file, (byte[]) obj);
                return file;
            } catch (IOException e) {
                throw new SQLException("Error at saving Blob to file", e);
            }
        }
        Blob blob = (Blob) obj;
        InputStream in = blob.getBinaryStream();
        try {
            return IOUtils.saveAsTempFile(in);
        } catch (IOException e) {
            throw new SQLException("Error at saving Blob to file", e);
        }
    }
}